{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Design a 4 qubit full chip"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Creates a complete quantum chip and exports it to GDS."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Preparations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The next cell enables [module automatic reload](https://ipython.readthedocs.io/en/stable/config/extensions/autoreload.html?highlight=autoreload). Your notebook will be able to pick up code updates made to the qiskit-metal (or other) module code."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%reload_ext autoreload\n",
    "%autoreload 2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Import key libraries and open the Metal GUI. Also, we configure the notebook to enable overwriting of existing components."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from collections import OrderedDict\n",
    "\n",
    "from qiskit_metal import designs, draw\n",
    "from qiskit_metal import MetalGUI, Dict, Headings\n",
    "\n",
    "design = designs.DesignPlanar()\n",
    "gui = MetalGUI(design)\n",
    "\n",
    "# if you disable the next line, then you will need to delete a component [<component>.delete()] before recreating it\n",
    "design.overwrite_enabled = True"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Import components that will be necessary for the design."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit_metal.qlibrary.qubits.transmon_pocket_cl import TransmonPocketCL\n",
    "from qiskit_metal.qlibrary.tlines.meandered import RouteMeander\n",
    "from qiskit_metal.qlibrary.tlines.anchored_path import RouteAnchors\n",
    "from qiskit_metal.qlibrary.tlines.pathfinder import RoutePathfinder\n",
    "from qiskit_metal.qlibrary.terminations.launchpad_wb import LaunchpadWirebond\n",
    "from qiskit_metal.qlibrary.terminations.launchpad_wb_coupled import LaunchpadWirebondCoupled"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Let's design the core of the chip"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Setup the design-wide default settings for trace width and trace gap. These can be customized later for individual transmission lines."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "design.variables['cpw_width'] = '10 um'\n",
    "design.variables['cpw_gap'] = '6 um'\n",
    "design._chips['main']['size']['size_y'] = '9mm'\n",
    "design._chips['main']['size']['size_y'] = '6.5mm'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We need 4 transmons with 3 connection pads each and a chargeline. Let's explore the options of one transmon"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "TransmonPocketCL.get_template_options(design)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We want to change the `pad_width` for these transmons, as well as define the 3 connection pads and chargeline.\n",
    "\n",
    "To apply the same modifications to all 4 transmons, we define a single option-dictionary to pass to all transmons at the monent of creation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "transmon_options = dict(\n",
    "    connection_pads=dict(\n",
    "        a = dict(loc_W=+1, loc_H=-1, pad_width='70um', cpw_extend = '50um'), \n",
    "        b = dict(loc_W=-1, loc_H=-1, pad_width='125um', cpw_extend = '50um'),\n",
    "        c = dict(loc_W=-1, loc_H=+1, pad_width='110um', cpw_extend = '50um')\n",
    "    ),\n",
    "    gds_cell_name='FakeJunction_01',\n",
    "    cl_off_center = '-50um',\n",
    "    cl_pocket_edge = '180'\n",
    ")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can now create the 4 transmons by specifying the desired coordinates and orientations."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "offset_tm = 69  #we the transmon slightly out of center-line\n",
    "\n",
    "q1 = TransmonPocketCL(design, 'Q1', options = dict(\n",
    "    pos_x='+2420um', pos_y=f'{offset_tm}um', **transmon_options))\n",
    "q2 = TransmonPocketCL(design, 'Q2', options = dict(\n",
    "    pos_x='0um', pos_y='-857.6um', orientation = '270', **transmon_options))\n",
    "q3 = TransmonPocketCL(design, 'Q3', options = dict(\n",
    "    pos_x='-2420um', pos_y=f'{offset_tm}um', orientation = '180', **transmon_options))\n",
    "q4 = TransmonPocketCL(design, 'Q4', options = dict(\n",
    "    pos_x='0um', pos_y='+857.6um', orientation = '90', **transmon_options))\n",
    "\n",
    "gui.rebuild()\n",
    "gui.autoscale()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's now connect the transmons with transmission lines. We want to have an \"exact length\" transmission line, so we will use the `RouteMeander`. Let's first observe what the default options are."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "RouteMeander.get_template_options(design)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We want to globally override the default lead (straight initial segment leaving the transmon) and the default fillet (corner rounding radius). Let's collect this information in one dictionary."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fillet='99.99um'\n",
    "cpw_options = Dict(\n",
    "    lead=Dict(\n",
    "        start_straight='100um',\n",
    "        end_straight='250um'),\n",
    "    fillet=fillet\n",
    "    )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We then want each transmission line to be connected to different pins and to have different lengths and asymmetry w.r.t their centerline. Let's collect this information in other dictionaries. Before doing that, to manage the dictionaries in a simpler way, we redefine the `RouteMeander` signature by wrapping it into a convenient method named `connect`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def connect(cpw_name: str, pin1_comp_name: str, pin1_comp_pin: str, pin2_comp_name: str, pin2_comp_pin: str,\n",
    "            length: str, asymmetry='0 um'):\n",
    "    \"\"\"Connect two pins with a CPW.\"\"\"\n",
    "    myoptions = Dict(\n",
    "        pin_inputs=Dict(\n",
    "            start_pin=Dict(\n",
    "                component=pin1_comp_name,\n",
    "                pin=pin1_comp_pin),\n",
    "            end_pin=Dict(\n",
    "                component=pin2_comp_name,\n",
    "                pin=pin2_comp_pin)),\n",
    "        total_length=length)\n",
    "    myoptions.update(cpw_options)\n",
    "    myoptions.meander.asymmetry = asymmetry\n",
    "    return RouteMeander(design, cpw_name, myoptions)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can now proceed and define the meanders following the signature: `connect(cpw_name, pin1_comp_name, pin1_comp_pin, pin2_comp_name, pin2_comp_pin, length, asymmetry)`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "asym = 500\n",
    "cpw1 = connect('cpw1', 'Q1', 'c', 'Q4', 'b', '9000um', f'-{asym-1.25*offset_tm}um')\n",
    "cpw2 = connect('cpw2', 'Q3', 'b', 'Q4', 'c', '9000um', f'+{asym-1.25*offset_tm}um')\n",
    "cpw3 = connect('cpw3', 'Q3', 'c', 'Q2', 'b', '9000um', f'-{asym+0.75*offset_tm}um')\n",
    "cpw4 = connect('cpw4', 'Q1', 'b', 'Q2', 'c', '9000um', f'+{asym+0.75*offset_tm}um')\n",
    "\n",
    "gui.rebuild()\n",
    "gui.autoscale()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Let's now connect the core elements to the launchpads"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First we setup the launchpad location and orientation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# V1 - Corners\n",
    "p1_c = LaunchpadWirebond(design, 'P1_C', options = dict(pos_x='3545um', pos_y='2812um', orientation='270', lead_length='0um'))\n",
    "p2_c = LaunchpadWirebond(design, 'P2_C', options = dict(pos_x='3545um', pos_y='-2812um', orientation='90', lead_length='0um'))\n",
    "p3_c = LaunchpadWirebond(design, 'P3_C', options = dict(pos_x='-3545um', pos_y='-2812um', orientation='90', lead_length='0um'))\n",
    "p4_c = LaunchpadWirebond(design, 'P4_C', options = dict(pos_x='-3545um', pos_y='2812um', orientation='270', lead_length='0um'))\n",
    "\n",
    "# V2\n",
    "p1_q = LaunchpadWirebondCoupled(design, 'P1_Q', options = dict(pos_x='4020um', pos_y='0', orientation='180', lead_length='30um'))\n",
    "p2_q = LaunchpadWirebondCoupled(design, 'P2_Q', options = dict(pos_x='-990um', pos_y='-2812um', orientation='90', lead_length='30um'))\n",
    "p3_q = LaunchpadWirebondCoupled(design, 'P3_Q', options = dict(pos_x='-4020um', pos_y='0', orientation='0', lead_length='30um'))\n",
    "p4_q = LaunchpadWirebondCoupled(design, 'P4_Q', options = dict(pos_x='990um', pos_y='2812um', orientation='270', lead_length='30um'))\n",
    "\n",
    "gui.rebuild()\n",
    "gui.autoscale()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then we route. First the V2 launchpads - Exchange Coupler Lines to Edges."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "asym = 150\n",
    "cpw_options = Dict(\n",
    "    lead=Dict(\n",
    "        start_straight='430um',\n",
    "        end_straight='0um'),\n",
    "    fillet=fillet\n",
    "    )\n",
    "ol1 = connect('ol1', 'Q1', 'a', 'P1_Q', 'tie', '8.6 mm', f'+{asym}um')\n",
    "ol3 = connect('ol3', 'Q3', 'a', 'P3_Q', 'tie', '8.6 mm', f'+{asym}um')\n",
    "\n",
    "asym = 200\n",
    "cpw_options = Dict(\n",
    "    lead=Dict(\n",
    "        start_straight='535um',\n",
    "        end_straight='0um'),\n",
    "    fillet=fillet\n",
    "    )\n",
    "ol2 = connect('ol2', 'Q2', 'a', 'P2_Q', 'tie', '8.6 mm', f'+{asym}um')\n",
    "ol4 = connect('ol4', 'Q4', 'a', 'P4_Q', 'tie', '8.6 mm', f'+{asym}um')\n",
    "\n",
    "gui.rebuild()\n",
    "gui.autoscale()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally we route the V1 launchpads - Chargelines to Corners."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We create the transmission lines between the corner launchpads and the qubit charge lines."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from collections import OrderedDict\n",
    "jogsA_in = OrderedDict()\n",
    "jogsA_in[0] = [\"L\", '200um']\n",
    "\n",
    "options_line_cl1 = {'pin_inputs': \n",
    "            {'start_pin': {'component': 'Q1', 'pin': 'Charge_Line'}, \n",
    "             'end_pin': {'component': 'P1_C', 'pin': 'tie'}},\n",
    "            'lead': {'start_straight': '120um', 'end_straight': '225um','start_jogged_extension': jogsA_in},\n",
    "            'fillet': fillet\n",
    "            }\n",
    "cl1 = RouteAnchors(design, 'line_cl1', options_line_cl1)\n",
    "\n",
    "options_line_cl3 = {'pin_inputs': \n",
    "            {'start_pin': {'component': 'Q3', 'pin': 'Charge_Line'}, \n",
    "             'end_pin': {'component': 'P3_C', 'pin': 'tie'}},\n",
    "            'lead': {'start_straight': '120um', 'end_straight': '225um', 'start_jogged_extension': jogsA_in},\n",
    "            'fillet': fillet\n",
    "            }\n",
    "cl3 = RouteAnchors(design, 'line_cl3', options_line_cl3)\n",
    "\n",
    "gui.rebuild()\n",
    "gui.autoscale()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "jogsB_in = OrderedDict()\n",
    "jogsB_in[0] = [\"L\", '300um']\n",
    "\n",
    "anchors2c = OrderedDict()\n",
    "anchors2c[0] = np.array([2, -2.5])\n",
    "\n",
    "options_line_cl2 = {'pin_inputs': \n",
    "            {'start_pin': {'component': 'Q2', 'pin': 'Charge_Line'}, \n",
    "             'end_pin': {'component': 'P2_C', 'pin': 'tie'}},\n",
    "            'lead': {'start_straight': '200um', 'end_straight': '225um',\n",
    "                     'start_jogged_extension': jogsB_in},\n",
    "            'anchors': anchors2c,\n",
    "            'fillet': fillet\n",
    "            }\n",
    "\n",
    "cl2 = RouteAnchors(design, 'line_cl2', options_line_cl2)\n",
    "\n",
    "anchors4c = OrderedDict()\n",
    "anchors4c[0] = np.array([-2, 2.5])\n",
    "\n",
    "options_line_cl4 = {'pin_inputs': \n",
    "            {'start_pin': {'component': 'Q4', 'pin': 'Charge_Line'}, \n",
    "             'end_pin': {'component': 'P4_C', 'pin': 'tie'}},\n",
    "            'lead': {'start_straight': '200um', 'end_straight': '225um',\n",
    "                     'start_jogged_extension': jogsB_in},\n",
    "            'anchors': anchors4c,\n",
    "            'fillet': fillet\n",
    "            }\n",
    "\n",
    "cl4 = RouteAnchors(design, 'line_cl4', options_line_cl4)\n",
    "\n",
    "gui.rebuild()\n",
    "gui.autoscale()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Export to GDS"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "QDesign enables GDS renderer during init. Let's see what the avilable option defaults are."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "a_gds = design.renderers.gds\n",
    "\n",
    "a_gds.options"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a_gds.options['no_cheese']['buffer'] = '50um'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Correct the path to point to the junction GDS that we intend to include in the output GDS. Then stream out all components in the design."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a_gds.options['path_filename'] = '../../resources/Fake_Junctions.GDS'\n",
    "a_gds.export_to_gds(\"Full_chip_design.gds\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#gui.main_window.close()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
